package com.example.demo;

import static com.example.demo.Contant.DEVICE_ID;
import static com.example.demo.Contant.MSG_SERVER_LOGIN;
import static com.example.demo.Contant.MSG_SERVER_LOGOUT;
import static com.example.demo.Contant.MSG_SERVER_LOGOUTING;
import static com.example.demo.Contant.SERVER_IP;
import static com.example.demo.Contant.SERVER_PORT;

import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;

public class NetworkUtil extends AsyncTask<Void, Void, Void> {
    private static final String TAG = "NetworkUtil";
    private Socket socket;
    private DataOutputStream outputStream;
    private DataInputStream inputStream;
    private Handler handler;
    private int networkState = 0;

    private static final int NET_STATE_LOGOUTING = 917;
    private static final int NET_STATE_CLOSING = 918;
    private static final int NET_STATE_ERROR = 919;
    private static final int NET_STATE_IDLE = 230;

    public enum VOICE_TYPE {
        START_VOICE_TYPE(0x80),
        MIDDLE_VOICE_TYPE(0x81),
        END_VOICE_TYPE(0x82);
        private final int value;

        VOICE_TYPE(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    }

    public NetworkUtil(Handler handler) {
        super();
        this.handler = handler;
    }

    public void logout() {
        networkState = NET_STATE_LOGOUTING;
    }

    private void sendLogout() throws IOException {
        //same data as login info
        byte[] loginData = new byte[9];
        ByteBuffer byteBuffer = ByteBuffer.wrap(loginData);
        byteBuffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
        byteBuffer.putInt(5);
        byteBuffer.put((byte) 0xE2);
        byteBuffer.putInt(DEVICE_ID);

        outputStream.write(loginData);
        outputStream.flush();
    }

    private void sendLoginInfo() throws IOException {
        byte[] loginData = new byte[9];
        ByteBuffer byteBuffer = ByteBuffer.wrap(loginData);
        byteBuffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
        byteBuffer.putInt(5);
        byteBuffer.put((byte) 0xE1);
        byteBuffer.putInt(DEVICE_ID);

        //dump loginData
        outputStream.write(loginData);
        outputStream.flush();
    }

    private void receiveData() throws IOException {
        byte[] lenBytes = new byte[4]; // 用于存储数据长度的4字节
        int totalBytesRead = 0; // 已读取的字节总数
        int dataLen = 0; // 数据长度

        // 首先读取数据长度的4字节
        while (totalBytesRead < lenBytes.length) {
            int bytesRead = inputStream.read(lenBytes, totalBytesRead, lenBytes.length - totalBytesRead);
            if (bytesRead == -1) {
                // 连接已关闭
                networkState = NET_STATE_CLOSING;
                throw new IOException("Connection closed by the server.");
            }
            totalBytesRead += bytesRead;
        }

        // 将读取的长度字节转换为int类型
        ByteBuffer lenByteBuffer = ByteBuffer.wrap(lenBytes);
        lenByteBuffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
        dataLen = lenByteBuffer.getInt();
        // dump lenBytes
        dumpData(lenBytes);
        Log.d(TAG, "receiveData: " + dataLen);

        // 根据数据长度读取数据内容
        byte[] data = new byte[dataLen];
        totalBytesRead = 0;

        while (totalBytesRead < dataLen) {
            int bytesRead = inputStream.read(data, totalBytesRead, dataLen - totalBytesRead);
            if (bytesRead == -1) {
                // 连接已关闭
                networkState = NET_STATE_CLOSING;
                throw new IOException("Connection closed by the server.");
            }
            totalBytesRead += bytesRead;
        }

        dumpData(data);
        // 处理接收到的数据
        processData(data);
    }

    private void dumpData(byte[] data) {
        StringBuilder sb = new StringBuilder();
        for (byte b : data) {
            sb.append(String.format("%02X ", b));
        }
        Log.d(TAG, "Received data: " + sb.toString());
    }

    // data format:  [senderId][type][message]
    private void processData(byte[] data) {
        ByteBuffer byteBuffer = ByteBuffer.wrap(data);
        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);

        if (data.length <= 4) {
            Log.e(TAG, "Received data is too short to process.");
            return;
        }

        byte type = byteBuffer.get();
        int senderId = byteBuffer.getInt();
        byte[] message = null;
        if (data.length > 5) {
            message = new byte[data.length - 5];
            byteBuffer.get(message);
        }
        handleMessage(senderId, type, message);
    }

    private void handleMessage(int senderId, byte type, byte[] message) {
        Log.d(TAG, "handleMessage: " + Integer.toHexString(senderId) + " " + Integer.toHexString(type & 0xff));
        // 根据type处理不同的操作
        switch ((int)(type & 0xff)) {
            case 0xE1: {
                // 处理登录响应
                if (senderId == DEVICE_ID) {
                    handler.sendMessage(handler.obtainMessage(MSG_SERVER_LOGIN, senderId, 0));
                }
            }
            break;

            case 0xE2: {
                if (senderId == DEVICE_ID) {
                    handler.sendMessage(handler.obtainMessage(MSG_SERVER_LOGOUTING, senderId, 0));
                    networkState = NET_STATE_CLOSING;
                }
            }
            break;

            case 0xF1: {
                Log.d(TAG, "handleMessage: sending peer id: " + senderId);
                ByteBuffer frameBuffer = ByteBuffer.wrap(message);
                int frameCnt = (int)frameBuffer.get();
                int voiceType = frameBuffer.get();

                if (voiceType == VOICE_TYPE.START_VOICE_TYPE.getValue()) {
                    // 首包
                } else if (voiceType == VOICE_TYPE.MIDDLE_VOICE_TYPE.getValue()) {
                    // 中间包
                } else if (voiceType == VOICE_TYPE.END_VOICE_TYPE.getValue()) {
                    // 结束包
                }
            }
            break;
            // 其他type处理...
            default:
                Log.d(TAG, "Received message from " + senderId + " with type " + type);
                break;
        }
    }

    @Override
    protected Void doInBackground(Void... voids) {
        try {
            socket = new Socket();
            socket.connect(new InetSocketAddress(SERVER_IP, SERVER_PORT), 5000); // 5秒连接超时

            Log.d(TAG, "doInBackground: connected to " + SERVER_IP + ":" + SERVER_PORT);

            if (socket.isConnected()) {
                outputStream = new DataOutputStream(socket.getOutputStream());
                inputStream = new DataInputStream(socket.getInputStream());

                // 发送登录信息
                sendLoginInfo();

                // 开启接收信息线程
                Thread t = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        while (!Thread.currentThread().isInterrupted()) {
                            try {
                                // 接收数据
                                receiveData();
                            } catch (IOException e) {
                                e.printStackTrace();
                                break;
                            }
                        }

                        Log.d(TAG, "run: ----------thread end");
                    }
                });

                t.start();

                while (true) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    Log.d(TAG, "doInBackground: " + networkState);

                    if (networkState == NET_STATE_CLOSING || networkState == NET_STATE_ERROR) {
                        if (inputStream != null) {
                            inputStream.close();
                            inputStream = null;
                        }
                        if (outputStream != null) {
                            outputStream.close();
                            outputStream = null;
                        }
                        if (socket != null) {
                            socket.close();
                            socket = null;
                        }

                        try {
                            t.join();
                        }catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        break;
                    }else if (networkState == NET_STATE_LOGOUTING) {
                        sendLogout();
                        networkState = NET_STATE_IDLE;
                    }
                }

                Log.d(TAG, "doInBackground: end");
                handler.sendMessage(handler.obtainMessage(MSG_SERVER_LOGOUT, DEVICE_ID, 0));
            }
        }catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    protected void onCancelled() {
        super.onCancelled();
        try {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
            if (socket != null) {
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
